#!/bin/bash
#THIS DRIVER WRITTEN FOR THE BAM 1020, FOR THE PURPOSE OF DATA COLLECTION
#AND TIME SETTING. UNLINKE THE NON-TS SERIES OF DRIVERS.
#FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
#UPDATE: 04/17/2013 CHANGED TO RUN TIME SETTING AT 55 MINUTES AFTER THE HOUR;
#-------------------------------------------------------------
#THIS FUNCTION DETERMINES THE ABSOLUTE PATH TO THIS BAM DRIVER
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# THIS IS THE FUNCTION CALLED IN THE EVENT THAT CTRL+C IS PRESSED
cleanup()
{
	echo "Caught Signal ... cleaning up."
		if !(rm -f Data/.locked > /dev/null); then
       			{
               		 exit 1
        		} 
		fi
	echo "Done cleanup ... quitting."
	exit 1
}
#THE DIAGNOSTIC DATA (DIAG) ROUTINE TAKES THE DATA STREAM FROM THE API 400E
#AND TESTS FOR THE RECOGNITION OF KEY WORDS IN EACH LINE OF OUTPUT.
#IF THE KEY WORD IS DETECTED ON THAT LINE, A TEST IS PERFORMED. 
#IF THE TEST SUGGESTS THAT AN ERROR CONDITION EXISTS BASED UPON THE ALLOWABLE
#RANGES SPECIFIED BY THE ARB CHECKSHEET, THE OFFENDING LINE IS WRITTEN OUT 
#TO A FILE IN THE Data DIRECTORY. THE NAME OF THE DESTINATION FILE IS
#errors{HH}. THE FILES CAN THEN BE PARSED AND UTILIZED BY ANY ALERT PROGRAM?DAEMON.
diag()
{
	thishour=`date "+%H"`
	lasthour=`date -d "last hour" "+%H"`
	thisalert="errors$thishour"
	echo "$data2" | grep -v \^\$ > "${DIR}/.${thishour}_${instance}_bam_config"
	this_point=$(echo "$data" | awk 'BEGIN {FS=","}{tot=$10+$11+$12+$13+$14+$15+$16+$17+$18+$19+$20}{ print tot }')
	if [ "$this_point" -gt "0" ]; then
		{
			echo "$rprt_nm has experienced an error: $data" >> "Data/${thisalert}"
			these_errors=''
		}
	fi
        #DEFINE THE QTOT VALUE
        this_qtot=`echo "$data" |  awk '{FS=","}{print $4+0}'`
	#DEFINE THE TEST OF QTOT BEING less tha or
	if !( bc <<< "$this_qtot < $qtotlow" || bc <<< "$this_qtot > $qtothigh" ); then
	{
		echo "$rprt_nm QTOT is out of range ($qtotlow - $qtothigh). Measured QTOT Value: $this_qtot" >> "Data/${thisalert}"
	}
	fi
	if [ -e ${DIR}/.${lasthour}_${instance}_bam_config ]; then
		{
			diff_count=$(diff "${DIR}/.${lasthour}_${instance}_bam_config" "${DIR}/.${thishour}_${instance}_bam_config" | wc -l)
				if [ "${diff_count}" -gt "9" ]; then
					{
						echo "$rprt_nm ${occurence} configuration changed from ${lasthour} to ${thishour}: " > ${DIR}/.bamcfgdlta_${instance}_${thishour} 
						echo "$rprt_nm ${occurence} configuration at ${lasthour} : " >> ${DIR}/.bamcfgdlta_${instance}_${thishour}
						echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" >> ${DIR}/.bamcfgdlta_${instance}_${thishour} 
						cat "${DIR}/.${lasthour}_${instance}_bam_config" | awk 'NF>0 { print }' >> ${DIR}/.bamcfgdlta_${instance}_${thishour}
						echo "$rprt_nm ${occurence} configuration at ${thishour} : " >> ${DIR}/.bamcfgdlta_${instance}_${thishour}
						echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" >> ${DIR}/.bamcfgdlta_${instance}_${thishour}
						cat "${DIR}/.${thishour}_${instance}_bam_config" | awk 'NF>0 { print }' >> ${DIR}/.bamcfgdlta_${instance}_${thishour}
						echo "$rprt_nm ${occurence} configuration has changed. See the attached details." >> "Data/${thisalert}"
					}
				fi
		}
	fi
}

#BEGIN WRITE
#THIS FUNCTION HANDELS READ RIGHT HANDSHAKES BETWEEN VARIOUS DRIVERS
#IN GENERAL, THE DATA IS PLACED IN THE VARIABLE $TIMESTAMP PRIOR TO CALL
#NEXT, IT OPENS THE DATA DIRECTORY AND LOOKS FOR THE .locked FILE
#IF IT EXISTS, IT HANGS OUT UNTIL IT DOESN'T EXIST. AT THAT POINT
#IT CREATES A .locked FILE, AND APPENDS TO THE DATA RECORD.
#FINALLY IT REMOVES THE .locked FILE IT HAS CREATED.
#THIS FUNCTION ALSO PARSES THE .DISABLED FILE IN THE DRIVER FOLDER
#AND TAKES A CHANNEL OFF LINE BY PREPENDING --DISABLED-- TO EACH LINE OF CONTENT IN THE DATA DIRECTORY
#written by MJV
write()
{
#CONFIRM THAT THERE IS NO HIDDEN FILE CALLED '.locked'
	while [ -e "Data/.locked" ];
		do
			sleep .2;
		done	
	echo "LOCKED" > "Data/.locked";
	this_alert="errors$thishour"
	#PARSE THE .disabled File
	channel_status=`cat "$DIR/.disabled${instance}"`
	#IF THE FILE DOSEN'T EXIT OR IS NOT ACCESIBLE
	#MAKES SURE A VALUE OF 0 IS USED
	if [ `expr $channel_status + 0` -eq 1 ]; then
		if [ -z `echo "$data" | awk '{RS=","}{ print $3 }'` ]; then
			echo "${timestamp}${rprt_nm}${occurrence} null detected...maybe the CARBLogger was unplugged... " >> "Data/${this_alert}"
			echo "${timestamp}${rprt_nm}${occurrence} may be disconnected BAM${occurrence}=999 --DISABLED--" >> "Data/${datafile}"
			
		else
			if !(echo "$data" | awk -v oc=$occurrence -v ts=$timestamp '{ print ts "BAM"oc"="$3*1000 " QTOT"oc"="$4" " $5" " $6 $7 $8 $9 $10 $1 " " $2 " --DISABLED--"}' >> "Data/${datafile}"); then
				echo "GENERAL FAILURE WRITING TO RECORD: $#";
				cleanup;
			fi		
		fi
		if !(echo "$data2" | sed 's/^/'$timestamp2'/g'| grep -v \:\:\:\$ | sed 's/$/'\ \-\-DISABLED\-\-'/g' >> "Data/$datafile" ); then
			{
			echo "GENERAL FAILURE WRITING TO RECORD: $#";
			cleanup;
			}
		fi
	
	else
	####################################################ROUTINE TO VERIFY NON_NULL DATA##############################
	# CARBLOGGER APPLIES A CORRECTION FACTOR OF 1000 FOR AQSB to BAM DATA TO TRANSLATE FROM UG TO MG. 		#
	# AN UNFORTUNATE CONSEQUENCE OF THIS IS THAT AWK WILL INTERPRET (1000)*(NULL) AS 0. THIS FUNCTION		#
	# WILL NOT APPLY THIS FACTOR IF A NULL VALUE IF PASSED								#
	################################################################################################################# 
	
		if [ -z `echo "$data" | awk '{RS=","}{ print $3 }'` ]; then
			{
				echo "${timestamp}${rprt_nm}${occurrence} null detected...maybe the CARBLogger was unplugged... " >> "Data/${this_alert}"
				echo "${timestamp}${rprt_nm}${occurrence} may be disconnected BAM${occurrence}=999 " >> "Data/${datafile}"
			}
			else
			{ 
				if !(echo "$data" | awk -v oc=$occurrence -v ts=$timestamp '{ print ts "BAM"oc"="$3*1000 " QTOT"oc"="$4" " $5" " $6 $7 $8 $9 $10 $1 " " $2 }' >> "Data/${datafile}"); then
					{
						echo "GENERAL FAILURE WRITING TO RECORD: $#";
						cleanup;
					}
				fi
				if !(echo "$data2" | sed 's/^/'$timestamp2'/g'| grep -v \:\:\:\$ >> "Data/$datafile" ); then
					{
						echo "GENERAL FAILURE WRITING TO RECORD: $#";
						cleanup;
					}
				fi
	   		}
	      	fi
		
	fi
	if !(rm -f "Data/.locked" > /dev/null ); then
		{	
			echo "GENERAL FAILURE REMOVING LOCK: $#";
			exit 1;	
		}
	fi
	if !(timestamp="" && data="" && data2="" ); then
		{
		echo "GENERAL FAILURE CLEARING WRITE BUFFER: $#";
		cleanup;
		}
	fi	
}
talk()
{

#Date stamp
today=`date "+%Y-%d-%m"`
timestamp=$rprt_nm::`date "+%m-%d-%Y_%H:%M"`:::
timestamp2=$rprt_nm::CONFIG::`date "+%m-%d-%Y_%H:%M"`:::
#THIS IS THE NAME OF THE DATA FILE RIGHT NOW
datafile="$saroad-$today"
#TALK TO THE INSTRUMENT, PRE-APPEND THE TIMESTAMP AND REPORTING NAME TO EACH
#LINE OF OUTPUT AND tee TO THE DATA FILE. FOR THE BAM, WE DO THIS TWICE AN HOUR.
#THE FIRST TIME WE GRAB LAST HOURS DATA. THE SECOND TIME WE GRAB THE INSTRUMENT CONFIG
data=`sjinn -d $dvc_prt -s $cmnd1 -w $wt_rsp1 -b $bd_rt -r$rsp_lngth $dtr $ctr $p8n1 | grep -e ^[0-9][0-9]\/[0-3][0-9]\/[0-9][0-9]` 
sleep 2
data2=`sjinn -d $dvc_prt -s "\\p\\r\\r\\r4\\p" -w 4 -b $bd_rt -r910 $dtr $ctr $p8n1` 
	if [ -z `echo "$data" | awk '{RS=","}{ print $3 }'` ]; then
		{
			sleep 60
			data=`sjinn -d $dvc_prt -s $cmnd1 -w $wt_rsp1 -b $bd_rt -r$rsp_lngth $dtr $ctr $p8n1 | grep -e ^[0-9][0-9]\/[0-3][0-9]\/[0-9][0-9]` 
			sleep 2
			data2=`sjinn -d $dvc_prt -s "\\p\\r\\r\\r4\\p" -w 4 -b $bd_rt -r910 $dtr $ctr $p8n1` 
				if [ -z `echo "$data" | awk '{RS=","}{ print $3 }'` ]; then
					{
						sleep 60
						data=`sjinn -d $dvc_prt -s $cmnd1 -w $wt_rsp1 -b $bd_rt -r$rsp_lngth $dtr $ctr $p8n1 | grep -e ^[0-9][0-9]\/[0-3][0-9]\/[0-9][0-9]` 
						sleep 2
						data2=`sjinn -d $dvc_prt -s "\\p\\r\\r\\r4\\p" -w 4 -b $bd_rt -r910 $dtr $ctr $p8n1` 
					
						if [ -z `echo "$data" | awk '{RS=","}{ print $3 }'` ]; then
							{
								sleep 60
								data=`sjinn -d $dvc_prt -s $cmnd1 -w $wt_rsp1 -b $bd_rt -r$rsp_lngth $dtr $ctr $p8n1 | grep -e ^[0-9][0-9]\/[0-3][0-9]\/[0-9][0-9]` 
								sleep 2
								data2=`sjinn -d $dvc_prt -s "\\p\\r\\r\\r4\\p" -w 4 -b $bd_rt -r910 $dtr $ctr $p8n1` 
							}
						fi
					}
				fi
		}
	fi
}

###################################################################################################
#
#BEGIN THE TIME CHECKING AND SETTING ROUTINE
#
###################################################################################################

checkandset()
{
		thishour=`date "+%H"`
		lasthour=`date -d "last hour" "+%H"`
		thisalert="errors$thishour"		
		#obtain the BAM time
		#ctime=`sjinn -b${bd_rt} -d ${dvc_prt} -s "\r\r\r\r\r\p5" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr`		
		#ctime=`echo $ctime | grep -o \ [0-9][0-9]:[0-9][0-9]`
		#obtain the carblogger time
		#sys_time=`echo $timestamp | grep -o _[0-9][0-9]:[0-9][0-9]::: | tr -d _ | sed 's/::://g'`
		#sys_seconds=`date -d $sys_time "+%s"`
		#bam_seconds=`date -d $ctime "+%s"`
		#diff_seconds=`echo "$sys_seconds-$bam_seconds" | bc`
		#abs_diff=`echo "sqrt($diff_seconds^2)" | bc`
		#min_diff=`echo "$abs_diff/60" | bc`
		#echo $min_diff 
		#THE FOLLOWING VARIABLE DETERMINES WHAT THE DATE STAMP SHOULD BE
		#13 SECONDS FROM NOW.
		if [ "$firmware_version" = "on" ] && [ "$thishour" = "23" ]; then	
			#WE NEED TO PASS NO SECOND STRING TO OLDER BAMS ONCE PER DAY
			set_time=`date -d "13 seconds" "+%H:%M"`
			sjinn -b${bd_rt} -d ${dvc_prt} -s "\r\r\r\r\8\pt\p1234\r\p${set_time}\r" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr
		elif [ "$firmware_version" = "" ]; then
			#WE NEED TO PASS A SECONDS STRING TO NEWER BAMS EVERY HOUR		
			set_time=`date -d "13 seconds" "+%H:%M:%S"`
			sjinn -b${bd_rt} -d ${dvc_prt} -s "\r\r\r\r\8\pt\p1234\r\p${set_time}\r" -r$rsp_lngth -w$wt_rsp1 $p8n1 $dtr $ctr
		fi	
		
		

}


#THIS IS THE ACTUAL COMMUNICATION WITH THE INSTRUMENT
#THE TIMER CONTROL. AT THE BEGINING IT TESTS FOR THE 
#EXISTENCE IF TOGGLE VARRIABLES WHICH ARE UTILIZED BOTH BY
#THE COMM ROUTINE runit() AND THE DIAGNOSTICS DATA ROUTINE
#diag()
runit()
{
#IF THE -d, -C, or -p variable is set to on, then append those parameters
#to the sjinn communication string. If the -i parameter is passed, diag will
#test for IZS specific routines.
if [ "$dtr_val" = "on" ]; then
 	dtr="--dtr" 
fi
if [ "$ctr_val" = "on" ]; then
 	ctr="--ctr"
fi
if [ "$p8n1_val" = "on" ]; then
 	p8n1="-p8n1"
fi
#Date stamp
talk
write
diag
}
#THIS IS THE FUNCTION RUN IN THE EVENT THAT THE REQUIRED PARAMETERS
#ARE NOT ENTERED.
usage()
{
clear
cat << EOF
usage: $0 options
OPTIONS:
-h	display help
-r	rprt_nm [rn]
-d	dvc_prt [eg, /dev/ttyS0, /dev/ttyUSB1]
-b	bd_rt [2400,4800,9600,etc.]
-c	cmnd1 (e.g, \r\r\r\p\6\4)
-m	min_val [two digit minute to run on EVERY HOUR]
-w	wt_rsp1 [seconds]
-l	rsp_lngth [characters]
-o	occurrence
-s	SAROAD number of the station
-t	[on/off] (OPTIONAL)
-C	[on/off] (OPTIONAL)
-p	[on/off] (OPTIONAL)
-f 	run time in minutes value [ie. 50=runtime for .834 QTOT or 42=runtime for .700 QTOT]
-2	For the BAM1020 firmware < 3, is set to on
Last updated 9/10/2009
EOF
}
#HELP FUNCTION GIVES BACKGROUND ON THIS DRIVER
help_me ()
{
clear
cat .help
exit 0
 }
def_opts ()
{
clear
cat .options
}

##CLEAR ALL VARIABLES               
rprt_nm= ; dvc_prt= ; bd_rt= ; cmnd1= ; wt_rsp1= ; bd_rt= ; rsp_lngth= ; 
dvc_prt= ; frqncy= ; dtr= ; ctr= ; p8n1= ; izs= ; saroad= ; p8n1= ; run_min= ;
instance=1 ; occurrence= ; firmware_version= ;

# set the default qtot values
qtot=50
qtotlow="0.830"
qtothigh="0.837"


##INITIALIZE THE BUFFER
return='NOT WRITTEN TO'
##loop through all variables and parameters
##Note that the position of the colon indicates the presence
##of a parameter to collect. The h parameter simply
##returns the help message.

while getopts “hr:s:d:b:c:w:l:t:C:p:m:I:o:2:f:” OPTION
do
case $OPTION in
s)
saroad=$OPTARG
;;
r)
rprt_nm=$OPTARG
;;
d)
dvc_prt=$OPTARG
;;
b)
bd_rt=$OPTARG
;;
c)
cmnd1=$OPTARG
;;
w)
wt_rsp1=$OPTARG
;;
l)
rsp_lngth=$OPTARG
;;
t)
dtr_val=$OPTARG
;;
C)
ctr_val=$OPTARG
;;
p)
p8n1_val=$OPTARG
;;
m)
run_min=$OPTARG
;;
o)
occurrence=$OPTARG
;;
I)
instance=$OPTARG
;;
f)
qtot=$OPTARG
if [ "$qtot" = "50" ]; then 
	{
		qtotlow="0.830"
	  	qtothigh="0.837"
	}
elif [ "$qtot" = "42" ]; then 
	{
		qtotlow=0.696
	  	qtothigh=0.704
	}
else
	{
		qtotlow=0.830
	  	qtothigh=0.837
	}
fi
;;
h)
help_me
exit 1
;;
2)
firmware_version=$OPTARG
	shopt -s nocasematch
	[[ $firmware_version == *on* ]] && firmware_version=on
	shopt -u nocasematch
 
;;
*)
usage
exit 1
;;
esac
done
#CHECK FOR THE CRITICAL PARAMETERS, IF THEY ARE NOT PRESENT THEN
#RUN THE USAGE FUNCTION WHICH RETURNS THE INSTRUCTIONS FOR PROPER USAGE
#MUST HAVE r n d b c w l i s
if [ -z "$rprt_nm" ] || [ -z "$dvc_prt" ] || [ -z "$bd_rt" ] || [ -z "$cmnd1" ] ||
[ -z "$wt_rsp1" ] || [ -z "$rsp_lngth" ] || [ -z "$saroad" ] || [ -z "$run_min" ] || 
[ -z "$firmware_version" ] || [ -z "$qtot" ]
	then
		{
		usage
		exit
		}
fi

	#INITIALIZED THE RAN VARIABLE. THIS IS USED TO TOGGLE THE TIMER GATE
ran=0
	#TRAP CTRL+C
trap cleanup 1 2 3 6 15
	#SETUP THE OPERATING LOOP
while :
do
	#SET THE MINUTE VARIABLE 
minute=`date "+%M"`
	#IF THE MINUTE VALUE IS THE TERM SPECIFIED, BEGIN RUNNING
if [ "$minute" -eq "$run_min" ] && [ "$ran" -eq "0" ]; then
	{
	#RUN THE RUNIT FUNCTION
		runit
	#TOGGLE THE RAN VARIABLE SO THAT THE PROCESS WILL NOT REPEAT
	#UNTIL THE BEGINNING OF THE NEXT MINUTE.
		ran=1
	#WAIT FOR COMPLETION OF THE RUNIT FUNCTION AND THE VARIABLE
	#SET
		sleep 60
	}
	#IF THE SECOND VALUE IS GREATER THAT 02, RESET RAN TO 0
	#AND WAIT ONE SECOND BEFORE CHECKING AGAIN

elif [ "$minute" -eq "55" ] && [ "$ran" -eq "0" ]; then
	{
	#RUN THE TIME CHECK AND SET FUNCTION EVERY HOUR
		checkandset	
	#TOGGLE THE RAN VARIABLE SO THAT THE PROCESS WILL NOT REPEAT
	#UNTIL THE BEGINNING OF THE NEXT MINUTE.
		ran=1
	#WAIT FOR COMPLETION OF THE RUNIT FUNCTION AND THE VARIABLE
	#SET
		sleep 60
	}
else 
	{
	#WAIT 15 SEC
		sleep 15
	#SET RAN TO 0
		ran=0
	}
fi
done;
exit;

